// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)

using System;
using System.Collections.Generic;

namespace NPack.Interfaces
{
    /// <summary>
    /// Provides an interface for an implementation to compute matrix operations.
    /// </summary>
    /// <typeparam name="T">Type of matrix element.</typeparam>
    /// <typeparam name="TVector">Type of vector.</typeparam>
    /// <typeparam name="TMatrix">Type of matrix.</typeparam>
    public interface IMatrixOperations<T, TVector, TMatrix>
        where T : IEquatable<T>, IComparable<T>, IComputable<T>, IConvertible
        where TVector : IVector<T>, IEquatable<TVector>, IComparable<TVector>, IComputable<Double, TVector>
        where TMatrix : IMatrix<T>, IEquatable<TMatrix>, IComparable<TMatrix>, IComputable<TMatrix>
    {
        /// <summary>
        /// Adds two matrixes and returns the result.
        /// </summary>
        /// <param name="lhs">First matrix to add.</param>
        /// <param name="rhs">Second matrix to add.</param>
        /// <value>lhs + rhs</value>
        /// <returns>
        /// The sum of the <paramref name="lhs"/> and <paramref name="rhs"/> matrixes.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the row count or column count of <paramref name="lhs"/> 
        /// does not equal the row count or column count of <paramref name="rhs"/>, respectively.
        /// </exception>
        TMatrix Add(TMatrix lhs, TMatrix rhs);

        /// <summary>
        /// Adds two vectors and returns the result.
        /// </summary>
        /// <param name="lhs">First vector to add.</param>
        /// <param name="rhs">Second vector to add.</param>
        /// <value>lhs + rhs</value>
        /// <returns>
        /// The sum of the <paramref name="lhs"/> and <paramref name="rhs"/> vectors.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the component count of <paramref name="lhs"/> 
        /// does not equal the component count of <paramref name="rhs"/>, respectively.
        /// </exception>
        TVector Add(TVector lhs, TVector rhs);

        /// <summary>
        /// Subtracts two matrixes and returns the result.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the subtraction operation.</param>
        /// <param name="rhs">Matrix on the right of the subtraction operation.</param>
        /// <value>lhs - rhs</value>
        /// <returns>
        /// The difference of the <paramref name="lhs"/> and <paramref name="rhs"/> matrixes.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the row count or column count of <paramref name="lhs"/> 
        /// does not equal the row count or column count of <paramref name="rhs"/>, respectively.
        /// </exception>
        TMatrix Subtract(TMatrix lhs, TMatrix rhs);

        /// <summary>
        /// Subtracts two vectors and returns the result.
        /// </summary>
        /// <param name="lhs">Vector on the left of the subtraction operation.</param>
        /// <param name="rhs">Vector on the right of the subtraction operation.</param>
        /// <value>lhs - rhs</value>
        /// <returns>
        /// The difference of the <paramref name="lhs"/> and <paramref name="rhs"/> vectors.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the component count of <paramref name="lhs"/> 
        /// does not equal the component count of <paramref name="rhs"/>, respectively.
        /// </exception>
        TVector Subtract(TVector lhs, TVector rhs);

        /// <summary>
        /// Multiplies two matrixes and returns the result.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the multiplication operation.</param>
        /// <param name="rhs">Matrix on the right of the multiplication operation.</param>
        /// <value>lhs * rhs</value>
        /// <returns>
        /// The product of multiplying <paramref name="lhs"/> by <paramref name="rhs"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        TMatrix Multiply(TMatrix lhs, TMatrix rhs);

        /// <summary>
        /// Multiplies two matrixes, with the result stored in the left matrix.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the multiplication operation.</param>
        /// <param name="rhs">Matrix on the right of the multiplication operation.</param>
        /// <value>lhs * rhs</value>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        void Multiply(ref TMatrix lhs, TMatrix rhs);

        /// <summary>
        /// Multiplies two matrixes, with the result stored in the right matrix.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the multiplication operation.</param>
        /// <param name="rhs">Matrix on the right of the multiplication operation.</param>
        /// <value>lhs * rhs</value>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        void Multiply(TMatrix lhs, ref TMatrix rhs);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVector">The column vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVector"/> is null.
        /// </exception>
        TVector Multiply(TMatrix multiplier, TVector columnVector);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in row form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="rowVector">The row vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVector"/> is null.
        /// </exception>
        TVector Multiply(TVector rowVector, TMatrix multiplier);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVector">The column vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVector"/> is null.
        /// </exception>
        void Multiply(TMatrix multiplier, T[] columnVector);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in row form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="rowVector">The row vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVector"/> is null.
        /// </exception>
        void Multiply(T[] rowVector, TMatrix multiplier);

        /// <summary>
        /// Multiplies a matrix by a series of matrixes, and returns the series of products.
        /// </summary>
        /// <param name="lhs">
        /// Matrix on the left of the multiplication operation.
        /// </param>
        /// <param name="rhs">
        /// A series of matrixes on the right of the multiplication operation.
        /// </param>
        /// <returns>
        /// An enumeration of the products of the <paramref name="lhs"/> 
        /// matrix multiplied by each <paramref name="rhs"/> matrix.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        IEnumerable<TMatrix> Multiply(TMatrix lhs, IEnumerable<TMatrix> rhs);

        /// <summary>
        /// Multiplies a series of matrixes by another matrix, and returns the series of products.
        /// </summary>
        /// <param name="lhs">
        /// A series of matrixes on the left of the multiplication operation.
        /// </param>
        /// <param name="rhs">
        /// Matrix on the right of the multiplication operation.
        /// </param>
        /// <returns>
        /// An enumeration of the products of each <paramref name="lhs"/> matrix 
        /// multiplied by the <paramref name="rhs"/> matrix.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        IEnumerable<TMatrix> Multiply(IEnumerable<TMatrix> lhs, TMatrix rhs);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVectors">The column vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVectors"/> is null.
        /// </exception>
        IEnumerable<TVector> Multiply(TMatrix multiplier, IEnumerable<TVector> columnVectors);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in row form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="rowVectors">The row vectors to multiply.</param>
        /// <returns>The vector products.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVectors"/> is null.
        /// </exception>
        IEnumerable<TVector> Multiply(IEnumerable<TVector> rowVectors, TMatrix multiplier);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVectorsComponents">
        /// The column vectors to multiply as an enumeration of 
        /// arrays of components.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVectorsComponents"/> is null.
        /// </exception>
        void Multiply(TMatrix multiplier, IEnumerable<T[]> columnVectorsComponents);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in row form.
        /// </summary>
        /// <param name="rowVectorsComponents">
        /// The row vectors to multiply as an enumeration of arrays of components.
        /// </param>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVectorsComponents"/> is null.
        /// </exception>
        void Multiply(IEnumerable<T[]> rowVectorsComponents, TMatrix multiplier);

        /// <summary>
        /// Multiplies a matrix by a scalar value.
        /// </summary>
        /// <param name="matrix">The matrix to multiply.</param>
        /// <param name="scalar">The scalar to multiply the matrix by.</param>
        /// <returns>The matrix product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        TMatrix ScalarMultiply(TMatrix matrix, T scalar);

        /// <summary>
        /// Computes the inverse of the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the inverse for.</param>
        /// <returns>
        /// The inverse of the given <paramref name="matrix"/>, if one exists. 
        /// If the matrix is non-square, the pseudo-inverse is returned.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        TMatrix Invert(TMatrix matrix);

        /// <summary>
        /// Negates a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to negate.</param>
        /// <returns>
        /// A matrix identical to <paramref name="matrix"/> except with each element negated.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        TMatrix Negate(TMatrix matrix);

        /// <summary>
        /// Performs the rotate linear operation on the given <paramref name="matrix"/>.
        /// </summary>
        /// <param name="matrix">Matrix to rotate.</param>
        /// <param name="axis">A vector describing the axis of rotation.</param>
        /// <param name="radians">The measure of the angle to rotate through.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null or <paramref name="axis"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="axis"/> vector has a 
        /// different number of components than the matrix rank.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the <paramref name="axis"/> vector has more 
        /// than one component with a value greater than 0.
        /// </exception>
        void Rotate(TMatrix matrix, TVector axis, Double radians);

        /// <summary>
        /// Performs the scale linear operation on a matrix.
        /// </summary>
        /// <param name="matrix">Matrix to scale.</param>
        /// <param name="scaleVector">A vector describing the magnitiudes of scale for each dimension.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null or <paramref name="scaleVector"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="scaleVector"/> has a different number of 
        /// components than the dimension of the linear transform submatrix of <paramref name="matrix"/>.
        /// </exception>
        void Scale(TMatrix matrix, TVector scaleVector);

        /// <summary>
        /// Performs the shear linear operation on a matrix.
        /// </summary>
        /// <param name="matrix">Matrix to shear.</param>
        /// <param name="shearVector">A vector describing the magnitiudes of shear for each dimension.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null or <paramref name="shearVector"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="shearVector"/> has a different number of 
        /// components than the dimension of the linear transform submatrix of <paramref name="matrix"/>.
        /// </exception>
        void Shear(TMatrix matrix, TVector shearVector);

        /// <summary>
        /// Performs the translate affine operation on a matrix.
        /// </summary>
        /// <param name="affineMatrix">Affine matrix to translate.</param>
        /// <param name="translateVector">A vector describing the magnitiudes of translations for each dimension.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="affineMatrix"/> is null or <paramref name="translateVector"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="translateVector"/> has a different number of 
        /// components than the dimension of the affine transform submatrix of <paramref name="affineMatrix"/>.
        /// </exception>
        void Translate(TMatrix affineMatrix, TVector translateVector);

        /// <summary>
        /// Computes the Frobenius norm on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The square root of the sum of the squares of each element 
        /// (or the square root of the sum of the squares 
        /// of the singluar values of the matrix).
        /// </value>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double FrobeniusNorm(TMatrix matrix);

        /// <summary>
        /// Computes the one-norm (or Manhattan norm) on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The maximum value of the sum of the absolute value 
        /// of the elements of each column.
        /// </value>
        /// <returns>The one-norm.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double OneNorm(TMatrix matrix);

        /// <summary>
        /// Computes the two-norm on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The largest singular value for a matrix, or the Euclidean norm for a vector.
        /// </value>
        /// <returns>The two-norm.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double TwoNorm(TMatrix matrix);

        /// <summary>
        /// Computes the infinity-norm on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The maximum value of the sum of the absolute value 
        /// of the elements of each row.
        /// </value>
        /// <returns>The infinity-norm.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double InfinityNorm(TMatrix matrix);

        /// <summary>
        /// Computes the determinant for a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the determinant for.</param>
        /// <returns>The determinant of the matrix, if one exists.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the matrix is not square.
        /// </exception>
        Double Determinant(TMatrix matrix);

        /// <summary>
        /// Computes the rank of a given matrix, disregarding negligable singluar values.
        /// </summary>
        /// <param name="matrix">The matrix to compute the rank for.</param>
        /// <returns>
        /// The rank of the given <paramref name="matrix"/>, not counting very small singular values.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Int32 Rank(TMatrix matrix);

        /// <summary>
        /// Computes the condition number for a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the condition number for.</param>
        /// <value>The condition number is a measure of the relative error in a solution for the matrix.</value>
        /// <returns>The condition number for the given <paramref name="matrix"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double Condition(TMatrix matrix);

        /// <summary>
        /// Computes the trace value of the given matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the trace for.</param>
        /// <value>The sum of the values in the diagonal of the matrix.</value>
        /// <returns>The value of the trace.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double Trace(TMatrix matrix);

        /// <summary>
        /// Solves a linear system.
        /// </summary>
        /// <param name="a">Coefficient matrix.</param>
        /// <param name="b">Result matrix.</param>
        /// <returns>
        /// A matrix of solutions to the unknowns in the matrixes.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="a"/> is null or if <paramref name="b"/> is null.
        /// </exception>
        TMatrix Solve(TMatrix a, TMatrix b);

        /// <summary>
        /// Solves the transpose of the linear system.
        /// </summary>
        /// <param name="a">Coefficient matrix.</param>
        /// <param name="b">Result matrix.</param>
        /// <returns>
        /// A matrix of solutions to the unknowns in the transposed matrixes.
        /// </returns>
        /// Thrown if <paramref name="a"/> is null or if <paramref name="b"/> is null.
        TMatrix SolveTranspose(TMatrix a, TMatrix b);

        /// <summary>
        /// Computes the transpose of a given matrix.
        /// </summary>
        /// <param name="matrix">The matrix to find the transpose of.</param>
        /// <returns>A matrix which is the transpose of <paramref name="matrix"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        TMatrix Transpose(TMatrix matrix);

        /// <summary>
        /// Sets the values of a <paramref name="target"/> matrix with those of
        /// a <paramref name="source"/> matrix.
        /// </summary>
        /// <param name="source">The matrix with the values to copy.</param>
        /// <param name="target">The matrix with the values to replace.</param>
        void SetMatrix(TMatrix source, TMatrix target);

        /// <summary>
        /// Computes an LU factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the LU factorization for.</param>
        /// <returns>
        /// An <see cref="ILUDecomposition{T, TMatrix}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        ILUDecomposition<T, TMatrix> GetLUDecomposition(TMatrix matrix);

        /// <summary>
        /// Computes a QR factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the QR factorization for.</param>
        /// <returns>
        /// An <see cref="IQRDecomposition{T, TMatrix}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IQRDecomposition<T, TMatrix> GetQRDecomposition(TMatrix matrix);

        /// <summary>
        /// Computes a Cholesky factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the Cholesky factorization for.</param>
        /// <returns>
        /// An <see cref="ICholeskyDecomposition{T, TMatrix}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        ICholeskyDecomposition<T, TMatrix> GetCholeskyDecomposition(TMatrix matrix);

        /// <summary>
        /// Computes a singluar value factorization (SVD) for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the singluar value factorization for.</param>
        /// <returns>
        /// An <see cref="ISingularValueDecomposition{T, TMatrix}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        ISingularValueDecomposition<T, TMatrix> GetSingularValueDecomposition(TMatrix matrix);

        /// <summary>
        /// Computes an eigenvalue factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the eigenvalue factorization for.</param>
        /// <returns>
        /// An <see cref="IEigenvalueDecomposition{T, TMatrix}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IEigenvalueDecomposition<T, TMatrix> GetEigenvalueDecomposition(TMatrix matrix);
    }
}